<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<title>d3 demo</title>
<style>
body{
margin:0;
padding:0;
overflow:hidden;
}
.menu-list{
	position:absolute;
	left:0;
	top:0;
	display:none;
	list-style:none;
	border:1px solid #dcdddd;
	padding:2px;
	background-color:#FFF;
}
.menu-list li{
	border-bottom:1px solid #ccc;
	padding:5px 10px;
	cursor:pointer;
}
.menu-list li:last-child{
	border-bottom:none;
}
.menu-list li:hover{
	color:#409eff;
	background-color:#ccc;
}
</style>
</head>
<body>
<script src="https://d3js.org/d3.v5.min.js"></script>
<script src="force.js"></script>
<script>
var width = window.innerWidth;
var height = window.innerHeight;

var datas = {
	nodes:[
		{id:1,r:30,pic:"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2690587153,2643787055&fm=26&gp=0.jpg"},
		{id:2,r:30,pic:"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2860640912,1833965317&fm=26&gp=0.jpg"},
		{id:3,r:30,pic:"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=297690209,1035022668&fm=26&gp=0.jpg"}
	],
	links:[{source:1,target:2},{source:1,target:3},],
};

var getDataList = {
	1:{
		nodes:[
			{id:4,r:30,pic:"https://ss2.bdstatic.com/70cFvnSh_Q1YnxGkpoWK1HF6hhy/it/u=2690587153,2643787055&fm=26&gp=0.jpg"},
			{id:5,r:30,pic:"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=2860640912,1833965317&fm=26&gp=0.jpg"},
		],
		links:[
			{source:1,target:4},
			{source:1,target:5},
		],
	},
};

var menu = ["百科","图谱","下钻"];

var menuList  = '<li id="wiki">百科</li><li id="atlas">图谱</li><li id="drilldown">下钻</li>';

var selectedId = null;

/*var simulation = d3.forceSimulation(nodes)
.force("link", d3.forceLink(links).id(d => d.id))
.force("charge", d3.forceManyBody().strength(-300))
.force("center", d3.forceCenter(width / 2, height / 2))
.force("collide", d3.forceCollide(100).strength(0.2).iterations(5))
.alphaDecay(0.0228)
.on("tick", () => ticked());*/
initData(datas.nodes,datas.links);
console.log(datas)

function initData(nodes,links){
	var simulation = d3.forceSimulation(nodes)
	.force("link", d3.forceLink(links).id(d => d.id))
	.force("charge", d3.forceManyBody().strength(-300))
	.force("center", d3.forceCenter(width / 2, height / 2))
	.force("collide", d3.forceCollide(100).strength(0.2).iterations(5))
	.alphaDecay(0.0228)
	.on("tick", () => ticked());
}

var svg = d3.select("body")
	.append("svg")
	.attr("width",width)
	.attr("height",height)
	.call(d3.zoom().scaleExtent([0.5, 1.5]).on("zoom",()=>{
			holders.attr("transform", d3.event.transform);
		})
	).on("click",()=>{
		menus.style("display","none");
	});
	
var defs = svg.append("defs");

function initLayout(){

}

var patterns = defs
	.selectAll("pattern.patternclass")
	.data(datas.nodes)
	.enter()
	.append("pattern")
	.attr("class","patternclass")
	.attr("id",d=>"ava"+d.id)
	.attr('patternUnits', 'objectBoundingBox')
	.attr("x", "0")
	.attr("y", "0")
	.attr("width", "1")
	.attr("height", "1");

var marker = defs
	.append("marker")
	.attr("id","marker")
	.attr("markerWidth",10)
	.attr("markerHeight",10)
	.attr("refX",36)
	.attr("refY",4)
	.attr("orient","auto")
	.attr("markerUnits","userSpaceOnUse")
	.append("path")
	.attr("d","M 0 0 8 4 0 8Z")
	.attr("fill", "steelblue");

patterns.append("image")
	.attr("xlink:href",d=>d.pic)
	.attr("src",d=>d.pic)
	.attr("width",d=>d.r*2)
	.attr("height",d=>d.r*2)
	.attr("preserveAspectRatio", "xMidYMin slice");

//总容器
var holders = svg.append("g")
	.attr("class","holders")
	.attr("width",width)
	.attr("height",height);
	
var edges = holders.selectAll("g.edge")
			.data(datas.links)
			.enter()
			.append("g")
			.attr("class","edge")
			.attr("fill","#bad4ed");
			
var links = edges.append("path")
			.attr("class","links")
			.style("marker-end", "url(#marker)")
			.attr("stroke","#bad4ed");

var nodes = holders.selectAll("circle.circleclass")
			.data(datas.nodes)
			.enter()
			.append("circle")
			.attr("class","circleclass")
			.attr("fill",d=>("url(#ava"+d.id+")"))
			.attr("r",d=>d.r)
			.attr("nodeid",d=>d.id)
			.attr("stroke","#ccc")
			.attr("stroke-width",2)
			.on("click",()=>{
				
			})
			.on("mouseover",function(){
				d3.select(this)
				.attr("stroke-width",6)
				.attr("stroke",'#c5dbf0');
			})
			.on("mouseout",function(){
				d3.select(this)
				.attr("stroke-width",2)
				.attr("stroke",'#ccc');
			})
			.on("contextmenu",function(){
				event = event || window.event;
                event.cancelBubble = true;
                event.returnValue = false;
				d3.event.preventDefault();//屏蔽右键菜单

				menus.style("left",d3.select(this).attr("cx")+"px")
					.style("top",d3.select(this).attr("cy")+"px")
					.style("display","block");
					
				selectedId = d3.select(this).attr("nodeid");
				
			})
			.call(
				d3.drag()
				.on("start",dragStart)
				.on("end",dragEnd)
				.on("drag",draged)
			);
				
			
var menus = d3.select("body").append("ul")
	.attr("class","menu-list")
	.attr("id","menuList")
	.html(menuList);

var drilldown = document.getElementById("drilldown");
drilldown.addEventListener("click",drilldownFn);

function drilldownFn(){
	if(selectedId){
		const obj = getDataList[selectedId];
		//if(obj) initData(obj.nodes,obj.links);
	}
}

function ticked(){
	nodes.attr("cx",d=>d.x)
	.attr("cy",d=>d.y);
	
	edges.attr("transform",d=>{
		return getTransform(d.source, d.target, getDis(d.source, d.target));
	});
	
	 links.attr("d", d => {
            return "M3,0 L"+getDis(d.source, d.target)+",0";
     });
}

// 求元素移动到目标位置所需要的 transform 属性值
function getTransform(source, target, _dis) {
    var r;
    if (target.x > source.x) {
        if (target.y > source.y) {
            r = Math.asin((target.y - source.y) / _dis)
        } else {
            r = Math.asin((source.y - target.y) / _dis);
            r = -r;
        }
    } else {
        if (target.y > source.y) {
            r = Math.asin((target.y - source.y) / _dis);
            r = Math.PI - r;
        } else {
            r = Math.asin((source.y - target.y) / _dis);
            r -= Math.PI;
        }
    }
    r = r * (180 / Math.PI);
    return "translate(" + source.x + "," + source.y + ")rotate(" + r + ")";
}

// 求两点间的距离
function getDis(s, t) {
    return Math.sqrt((s.x - t.x) * (s.x - t.x) + (s.y - t.y) * (s.y - t.y));
}
		
function dragStart(d){
	d3.event.sourceEvent.stopPropagation();
	if (!d3.event.active) simulation.alphaTarget(0.3).restart();
	d.fx = d.x;
    d.fy = d.y;
}
function dragEnd(d){
	if (!d3.event.active) simulation.alphaTarget(0);
	d.fx = null;
    d.fy = null;
}
function draged(d){
	d.fx = d3.event.x;
    d.fy = d3.event.y;
}	
</script>
</body>
</html>